package com.avecsys.quotemanager.dao.supplier;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException;

import com.avecsys.quotemanager.constants.BusinessCodes;
import com.avecsys.quotemanager.dao.common.BaseDAOImpl;
import com.avecsys.quotemanager.dao.common.EnumDBRecordStatus;
import com.avecsys.quotemanager.dao.common.EnumTransactionStatus;
import com.avecsys.quotemanager.exception.BusinessException;
import com.avecsys.quotemanager.exception.DAOException;
import com.avecsys.quotemanager.pojos.BasePojo;
import com.avecsys.quotemanager.pojos.BuyerMasterPojo;
import com.avecsys.quotemanager.pojos.QuoteTransactionEventsPojo;
import com.avecsys.quotemanager.pojos.QuoteTransactionPojo;
import com.avecsys.quotemanager.pojos.SupplierMasterPojo;
import com.avecsys.quotemanager.utils.TransactionStatus;
import com.avecsys.quotemanager.vo.QuoteVO;

/**
 * @author Sam Sundar k
 */
public class QuoteTransactionDAOImpl extends BaseDAOImpl implements QuoteTransactionDAO
{
	private static final Log log = LogFactory.getLog(QuoteTransactionDAOImpl.class);

	/**
	 * Method to save the Quote Transaction and Quote Transaction Event
	 * 
	 * @param quoteTransactionsPojo
	 * @return TransactionStatus
	 * @throws BusinessException
	 */
	@Override
	public TransactionStatus saveQuoteTransaction(final QuoteTransactionPojo quoteTransactionPojo)
			throws DAOException
	{
		TransactionStatus transactionStatus = new TransactionStatus(
				EnumTransactionStatus.SAVE_SUCESS.ordinal());
		try
		{
			getHibernateTemplate().execute(new HibernateCallback<QuoteTransactionPojo>()
			{
				@Override
				public QuoteTransactionPojo doInHibernate(Session session) throws HibernateException,
						SQLException
				{
					// 1. Save Company Information
					session.save(quoteTransactionPojo);
					// 2. Save Default Administrator Supplier User Information
					for (QuoteTransactionEventsPojo quoteTransactionEventsPojo : quoteTransactionPojo.getQuoteTransactionEventsPojoSet())
					{
						quoteTransactionEventsPojo.setQuoteTransactionPojo(quoteTransactionPojo);
						session.save(quoteTransactionEventsPojo);
					}
					return quoteTransactionPojo;
				}
			});
		}
		catch (Exception e)
		{
			log.error(e);
			transactionStatus.setStatus(EnumTransactionStatus.SAVE_FAIL.ordinal());
			throw new DAOException(e);
		}
		return transactionStatus;
	}

	/**
	 * Method to list all Sent Quotes of buyers belong to a supplier
	 * 
	 * @param supplierMasterPojo
	 * @return List<QuoteTransactionPojo>
	 * @throws DAOException
	 */
	@Override
	public List<QuoteTransactionPojo> findAllSentQuotes(final SupplierMasterPojo supplierMasterPojo)
			throws DAOException
	{
		return getHibernateTemplate().execute(new HibernateCallback<List<QuoteTransactionPojo>>()
		{
			@Override
			public List<QuoteTransactionPojo> doInHibernate(Session session) throws HibernateException,
					SQLException
			{
				Query query = session.createQuery("from QuoteTransactionPojo quoteTransactionPojo"
						+ " join fetch quoteTransactionPojo.supplierMasterPojo supplierMasterPojo"
							+ " join fetch quoteTransactionPojo.buyerMasterPojo buyerMasterPojo"
							+ "	join fetch buyerMasterPojo.companyMasterPojo companyMasterPojo"
							+ "	where supplierMasterPojo.supplierId=:supplierId"
							+ "	and quoteTransactionPojo.status=:status"
							+ " order by quoteTransactionPojo.modifiedDttm");
				query.setLong("supplierId", supplierMasterPojo.getSupplierId());
				query.setString("status", EnumDBRecordStatus.ACTIVE.status());
				return (List<QuoteTransactionPojo>) query.list();
			}
		});
	}

	/**
	 * Method to list all Sent Quotes of buyers belong to a supplier
	 * 
	 * @param buyerMasterPojo
	 * @return List<QuoteTransactionEventsPojo>
	 * @throws DAOException
	 */
	@Override
	public List<QuoteTransactionEventsPojo> findAllQuoteEventsForBuyerAction(
			final BuyerMasterPojo buyerMasterPojo) throws DAOException
	{
		return getHibernateTemplate().execute(new HibernateCallback<List<QuoteTransactionEventsPojo>>()
		{
			@Override
			public List<QuoteTransactionEventsPojo> doInHibernate(Session session)
					throws HibernateException, SQLException
			{
				Query query = session.createQuery("from QuoteTransactionEventsPojo quoteTransactionEventsPojo"
						+ "	join fetch quoteTransactionEventsPojo.quoteTransactionPojo quoteTransactionPojo"
							+ " join fetch quoteTransactionPojo.buyerMasterPojo buyerMasterPojo"
							+ " join fetch quoteTransactionPojo.supplierMasterPojo supplierMasterPojo"
							+ "	join fetch supplierMasterPojo.companyMasterPojo companyMasterPojo"
							+ "	where buyerMasterPojo.buyerId=:buyerId"
							+ "	and quoteTransactionEventsPojo.transactionStatus in (:transactionStatus)");
				query.setLong("buyerId", buyerMasterPojo.getBuyerId());
				List<String> transactionStatusList = new ArrayList<String>();
				transactionStatusList.add(BusinessCodes.QUOTE_EVENT_TRANSACTION_STATUS_PENDING);
				query.setParameterList("transactionStatus", transactionStatusList);
				return query.list();
			}
		});
	}

	/**
	 * Method to update the Buyers Action (Accept,Amend or Ignore)on Reply Quote Action.
	 * 
	 * @param quoteTransactionEventsPojo
	 * @return TransactionStatus
	 * @throws DAOException
	 */
	@Override
	public TransactionStatus updateBuyerReply(final QuoteTransactionEventsPojo quoteTransactionEventsPojo)
			throws DAOException
	{
		TransactionStatus transactionStatus = new TransactionStatus(
				EnumTransactionStatus.UPDATE_SUCCESS.ordinal());
		try
		{
			getHibernateTemplate().execute(new HibernateCallback<Object>()
			{
				@Override
				public Object doInHibernate(Session session) throws HibernateException, SQLException
				{
					session.update(quoteTransactionEventsPojo);
					session.update(quoteTransactionEventsPojo.getQuoteTransactionPojo());
					return quoteTransactionEventsPojo;
				}
			});
		}
		catch (HibernateOptimisticLockingFailureException holfe)
		{
			log.error(holfe);
			transactionStatus.setStatus(EnumTransactionStatus.OPTIMIST_LOCK_FAIL.ordinal());
		}
		catch (Exception e)
		{
			e.printStackTrace();
			log.error(e);
			transactionStatus.setStatus(EnumTransactionStatus.UPDATE_FAIL.ordinal());
			throw new DAOException(e);
		}
		return transactionStatus;
	}

	@Override
	public QuoteTransactionEventsPojo findQuoteTransactionEventsById(final Long eventId)
			throws DAOException
	{
		return getHibernateTemplate().execute(new HibernateCallback<QuoteTransactionEventsPojo>()
		{
			@Override
			public QuoteTransactionEventsPojo doInHibernate(Session session) throws HibernateException,
					SQLException
			{
				Query query = session.createQuery("from QuoteTransactionEventsPojo quoteTransactionEventsPojo"
						+ "	join fetch quoteTransactionEventsPojo.quoteTransactionPojo quoteTransactionPojo"
							+ "	where quoteTransactionEventsPojo.eventId=:eventId");
				query.setLong("eventId", eventId);
				return (QuoteTransactionEventsPojo) query.uniqueResult();
			}
		});
	}

	/**
	 * Method to List all QuoteEvents for a Quote Transaction
	 * 
	 * @param quoteTransactionPojo
	 * @return List<QuoteTransactionEventsPojo>
	 * @throws DAOException
	 */
	@Override
	public List<QuoteTransactionEventsPojo> findAllQuoteEvents(
			final QuoteTransactionPojo quoteTransactionPojo) throws DAOException
	{
		return getHibernateTemplate().execute(new HibernateCallback<List<QuoteTransactionEventsPojo>>()
		{
			@Override
			public List<QuoteTransactionEventsPojo> doInHibernate(Session session)
					throws HibernateException, SQLException
			{
				Query query = session.createQuery("from QuoteTransactionEventsPojo quoteTransactionEventsPojo"
						+ "	join fetch quoteTransactionEventsPojo.quoteTransactionPojo quoteTransactionPojo"
							+ " join fetch quoteTransactionPojo.buyerMasterPojo buyerMasterPojo"
							+ "	join fetch buyerMasterPojo.companyMasterPojo companyMasterPojo"
							+ "	where quoteTransactionPojo.quoteId=:quoteId"
							+ "	order by quoteTransactionEventsPojo.eventId");
				query.setLong("quoteId", quoteTransactionPojo.getQuoteId());
				return query.list();
			}
		});
	}

	/**
	 * Method to create a new Quote Transaction event and update the master with child transaction status
	 * 
	 * @param quoteVO
	 * @return TransactionStatus
	 * @throws DAOException
	 */
	@Override
	public TransactionStatus createQuoteEvent(final QuoteVO quoteVO) throws DAOException
	{
		TransactionStatus transactionStatus = new TransactionStatus(
				EnumTransactionStatus.BATCH_SUCCESS.ordinal());
		try
		{
			getHibernateTemplate().execute(new HibernateCallback<Object>()
			{
				@Override
				public Object doInHibernate(Session session) throws HibernateException, SQLException
				{
					for (BasePojo basePojo : quoteVO.getPersistentList())
					{
						session.saveOrUpdate(basePojo);
					}
					return quoteVO;
				}
			});
		}
		catch (HibernateOptimisticLockingFailureException holfe)
		{
			log.error(holfe);
			transactionStatus.setStatus(EnumTransactionStatus.OPTIMIST_LOCK_FAIL.ordinal());
		}
		catch (Exception e)
		{
			log.error(e);
			transactionStatus.setStatus(EnumTransactionStatus.BATCH_SUCCESS.ordinal());
			throw new DAOException(e);
		}
		return transactionStatus;
	}

	/**
	 * Method to fetch all QuoteTransactionPojos the belong to a buyer by transaction status
	 * 
	 * @param buyerMasterPojo
	 * @param transactionStatus
	 * @return List<QuoteTransactionPojo>
	 */
	@Override
	public List<QuoteTransactionPojo> findAllQuoteTransactionPojos(
			final BuyerMasterPojo buyerMasterPojo, final List<String> transactionStatusList)
			throws DAOException
	{
		return getHibernateTemplate().execute(new HibernateCallback<List<QuoteTransactionPojo>>()
		{
			@Override
			public List<QuoteTransactionPojo> doInHibernate(Session session) throws HibernateException,
					SQLException
			{
				Query query = session.createQuery("from QuoteTransactionPojo quoteTransactionPojo"
						+ " join fetch quoteTransactionPojo.supplierMasterPojo supplierMasterPojo"
							+ " join fetch quoteTransactionPojo.buyerMasterPojo buyerMasterPojo"
							+ "	join fetch supplierMasterPojo.companyMasterPojo companyMasterPojo"
							+ "	where buyerMasterPojo.buyerId=:buyerId"
							+ "	and quoteTransactionPojo.transactionStatus in (:transactionStatus)"
							+ "	and quoteTransactionPojo.status=:status"
							+ " order by supplierMasterPojo.supplierId, quoteTransactionPojo.modifiedDttm");
				query.setLong("buyerId", buyerMasterPojo.getBuyerId());
				query.setParameterList("transactionStatus", transactionStatusList);
				query.setString("status", EnumDBRecordStatus.ACTIVE.status());
				return (List<QuoteTransactionPojo>) query.list();
			}
		});
	}
}
